package com.wanger.swc.config.myBatisPlus.autoDDL;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.wanger.swc.config.myBatisPlus.autoDDL.model.*;
import com.wanger.swc.exception.BusEx;
import org.anyline.service.AnylineService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: wanger
 * @Date: 2025/1/17 14:56
 * @Description: 启动类调用的接口
 */
public interface AutoDDLService {
    Logger log = LoggerFactory.getLogger(AutoDDLService.class);

    /**
     * 数据库类型
     *
     * @return 数据库类型
     */
    MyDBType getContentType();

    /**
     * 获取java类型对应的该数据库的字段类型
     *
     * @param javaType java类型
     * @return 数据库字段类型
     */
    String getDataType(Field javaType);

    /**
     * 获取该类型的字段类型映射
     *
     * @return 字段类型映射
     */
    List<FieldMapper> getFieldMappers();

    /**
     * 去除表名前缀，按前缀列表顺序匹配第一个符合的前缀进行替换
     *
     * @param myTables 原始表名列表
     * @param prefixes 需去除的前缀列表（按匹配优先级顺序）
     */
    default void removePrefixes(List<MyTable> myTables, Set<String> prefixes) {
        for (MyTable table : myTables) {
            String processedTable = table.getOriginalTableName();
            // 遍历前缀列表，按顺序匹配第一个符合的前缀
            for (String prefix : prefixes) {
                if (processedTable.startsWith(prefix)) {
                    processedTable = processedTable.substring(prefix.length());
                    break; // 匹配后立即终止检查其他前缀
                }
            }
            table.setTableName(processedTable);
        }
    }

    /**
     * 获取指定schema的所有表
     *
     * @param dbService 数据库连接
     * @return 返回表列表
     */
    default List<MyTable> getAllTable(AnylineService<?> dbService) {
        List<FieldMapper> mapperList = getFieldMappers();
        return dbService.metadata()
                .tables()
                .values()
                .parallelStream()
                .map(table -> {
                    Set<String> importSet = new HashSet<>();
                    List<MyColumn> collect = dbService.metadata()
                            .columns(table.getName())
                            .values()
                            .stream()
                            .map(column -> {
                                FieldMapper type = getType(mapperList, column.getOriginType());
                                List<String> packageList = type.getImportPackage();
                                if (CollUtil.isNotEmpty(packageList)) importSet.addAll(packageList);
                                return new MyColumn(column.getName(),
                                        column.getOriginType(),
                                        type.getJavaType(),
                                        column.getComment());
                            }).collect(Collectors.toList());
                    return new MyTable(table.getName(),
                            table.getComment(),
                            importSet,
                            collect);
                }).collect(Collectors.toList());
    }

    /**
     * 按类型通过正则表达式匹配对应的java类型字段
     *
     * @param list 字段类型映射
     * @param type 数据库字段类型
     * @return FieldMapper
     */
    default FieldMapper getType(List<FieldMapper> list, String type) {
        if (StrUtil.isBlank(type)) {
            BusEx.throwEx("请检查【{}】类的getQueryFieldsByTableNameSQL()方法配置的sql，该sql查询到了空类型！", this.getClass().getName());
        }
        for (FieldMapper mapper : list) {
            if (ReUtil.contains(mapper.getColumnTypeRegex(), type)) {
                return mapper;
            }
        }
        return new FieldMapper("", "Object");
        //throw BusEx.create("请在【{}】类的getFieldMappers()方法配置【{}】对应的java类型！", this.getClass().getName(), type);
    }

    /**
     * 排除配置的表
     *
     * @param list   原始列表
     * @param tables 排除表
     * @return 排除后的列表
     */
    default List<MyTable> exclusionTable(List<MyTable> list, Set<String> tables) {
        return list.stream().filter(it -> !tables.contains(it.getOriginalTableName())).collect(Collectors.toList());
    }

    /**
     * 验证指定数据库信息是否能正常连接到数据库
     *
     * @param dbService 数据库服务
     */
    default void verify(AnylineService<?> dbService) {
        dbService.validity();
    }

    /**
     * 将数据库表结构转换为json数据对象
     *
     * @param dbService      数据库服务
     * @param exclusionTable 排除表
     * @param tablePrefix    表前缀
     * @return json数据对象
     */
    default Object getJsonData(AnylineService<?> dbService, String exclusionTable, String tablePrefix) {
        List<MyTable> list = this.getAllTable(dbService);
        //排除表
        if (StrUtil.isNotBlank(exclusionTable)) {
            list = this.exclusionTable(list, Arrays.stream(exclusionTable.split(","))
                    .filter(StrUtil::isNotBlank).map(String::trim).map(String::toLowerCase).collect(Collectors.toSet()));
        }
        //移除表前缀
        if (StrUtil.isNotBlank(tablePrefix)) {
            this.removePrefixes(list, Arrays.stream(tablePrefix.split(","))
                    .filter(StrUtil::isNotBlank).map(String::trim).collect(Collectors.toSet()));
        } else list.forEach(it -> it.setTableName(it.getOriginalTableName()));
        return list;
    }
}
